//
// Created by starry on 2025/5/29.
//

#include <opencv2/imgproc.hpp>
#include <ReadBarcode.h>
#include <iostream>
#include "processor/QRPickDetector.h"



double QRPickDetector::getScaleFactorValue(double qrSideLength, int index) {
    return m_qrSideLengths[index] / qrSideLength; // 获取第一个qr的边长
}

cv::Mat QRPickDetector::getMarkedImage() {
    return m_markedImage;
}

bool QRPickDetector::isContainsQRCode(const cv::Mat& inputImage) {
    // 清空历史数据
    m_markedImage.release();
    m_extractedROIs.clear();
    m_allQrCorners.clear();
    m_qrSideLengths.clear();
    m_qrContents.clear();

    if (inputImage.empty()) {
        return false;
    }

    cv::Mat gray;

    cv::cvtColor(inputImage, gray, cv::COLOR_BGR2GRAY); // 灰度
    cv::GaussianBlur(gray, gray, cv::Size(3,3), 0); // 轻度降噪
    cv::normalize(gray, gray, 0, 255, cv::NORM_MINMAX); // 对比度拉伸

    // 使用ZXing检测二维码
    auto bitmap = ZXing::ImageView(gray.data, gray.cols, gray.rows, ZXing::ImageFormat::Lum);
    ZXing::DecodeHints hints;
    hints.setTryHarder(true);
    hints.setFormats(ZXing::BarcodeFormat::QRCode);

    m_results = ZXing::ReadBarcodes(bitmap, hints);

    gray.release();
    if (m_results.empty()) {
        std::cerr << "No QR code detected." << std::endl;
        return false;
    }

    // 准备标记图像
    m_markedImage = inputImage.clone();

    return true;
}

void QRPickDetector::generateQRParams() {
    // 处理每个检测到的二维码 绘制信息
    for (const auto& result : m_results) {
        if (!result.isValid())  {
            continue;
        }

        // 获取二维码的四个角点
        auto position = result.position();
        if (position.size() != 4) {
            continue;  // 确保有4个角点
        }

        // 转换为OpenCV的点格式
        std::vector<cv::Point> qrCorners;
        for (const auto& pt : position) {
            qrCorners.emplace_back(pt.x,  pt.y);
        }
        m_allQrCorners.push_back(qrCorners);

        std::cout << "qrCorners: " << qrCorners << std::endl;

        // 存储二维码内容
        std::string qrContent = result.text();
        m_qrContents.push_back(qrContent);

        // 计算底部边长（BL到BR的距离） 四个边均值
        double sideLength = cv::norm(qrCorners[3] - qrCorners[2]);
        std::cout << "Bottom side length: " << sideLength << " pixels" << std::endl;
        double avgLength = calculateAverageSideLength(qrCorners);
        std::cout << "Average side length: " << avgLength << " pixels" << std::endl;
        m_qrSideLengths.push_back(avgLength);

        // 绘制二维码边框（红色）
        cv::polylines(m_markedImage, std::vector<std::vector<cv::Point>>{qrCorners},true, cv::Scalar(44, 44, 238), 2);

//        // 在二维码中心显示编号
//        cv::Point center(0, 0);
//        for (const auto& pt : qrCorners) {
//            center += pt;
//        }
//        center.x /= 4;
//        center.y /= 4;
//
//        cv::putText(m_markedImage,
//                    std::to_string(m_qrContents.size()),
//                    center,
//                    cv::FONT_HERSHEY_SIMPLEX,
//                    1,
//                    cv::Scalar(0, 0, 255),
//                    2);

        // 从qr左边开始显示二维码内容
        displayQrContentOnSide(m_markedImage, qrContent, qrCorners);
    }

}

void
QRPickDetector::displayQrContentOnSide(cv::Mat& image, const std::string& qrContent, const std::vector<cv::Point>& qrCorners) {
    if (qrCorners.size()  != 4) {
        std::cerr << "Invalid number of QR code corners." << std::endl;
        return;
    }

    // 获取二维码右上角点的坐标
    cv::Point topRight = qrCorners[1];

    // 设置文字显示的位置，这里假设显示在二维码的上侧
    cv::Point textPos(topRight.x - 20, topRight.y + 20);

    // 设置字体、字号、颜色等参数
    int fontFace = cv::FONT_HERSHEY_SIMPLEX;
    double fontScale = 0.5;
    cv::Scalar fontColor = cv::Scalar(34, 139, 34); // 绿色
    int thickness = 2;

    // 在图像上绘制文字
    cv::putText(image, qrContent, textPos, fontFace, fontScale, fontColor, thickness);
}

double
QRPickDetector::calculateAverageSideLength(const std::vector<cv::Point>& qrCorners) {
    // 1. 参数检查
    if (qrCorners.size()  != 4) {
        throw std::invalid_argument("Exactly 4 corner points required");
    }

    // 2. 转换为浮点坐标进行计算（提高精度）
    std::vector<cv::Point2f> cornersFloat;
    cornersFloat.reserve(4);
    for (const auto& pt : qrCorners) {
        cornersFloat.emplace_back(static_cast<float>(pt.x),  static_cast<float>(pt.y));
    }

    // 3. 计算四条边长（确保顺序连续）
    std::array<double, 4> sideLengths;
    for (int i = 0; i < 4; ++i) {
        int nextIdx = (i + 1) % 4;
        sideLengths[i] = cv::norm(cornersFloat[nextIdx] - cornersFloat[i]);
    }

    // 4. 计算平均值（使用Kahan算法提高数值精度）
    double sum = 0.0;
    double compensation = 0.0;
    for (double len : sideLengths) {
        double y = len - compensation;
        double t = sum + y;
        compensation = (t - sum) - y;
        sum = t;
    }

    // 5. 有效性验证（边长差异不应超过10%）
    double avg = sum / 4.0;
    double threshold = avg * 0.1;
    for (double len : sideLengths) {
        if (std::abs(len - avg) > threshold) {
            throw std::runtime_error("Invalid QR code: side lengths mismatch");
        }
    }

    return avg;
}


void QRPickDetector::processSingleQR(const std::vector<cv::Point>& qrCorners, double qrBottomToChannelCenter, double width, double height){
    // 1. 完整转换为浮点坐标
    std::vector<cv::Point2f> qrCornersFloat;
    for (const auto& pt : qrCorners) {
        qrCornersFloat.emplace_back(pt.x, pt.y);
    }

    // 2. 使用浮点坐标进行计算
    const cv::Point2f& bottomLeft = qrCornersFloat[3]; // BL
    const cv::Point2f& bottomRight = qrCornersFloat[2]; // BR

    // 3. 计算几何参数
    cv::Point2f baseVec = bottomRight - bottomLeft;
    float angle = atan2(baseVec.y, baseVec.x);
    cv::Point2f perpendicularDir(-sin(angle), cos(angle));
    cv::Point2f baseMid = (bottomLeft + bottomRight) * 0.5f;
    cv::Point2f roiCenter = baseMid + perpendicularDir * (qrBottomToChannelCenter);

    // 4. 计算ROI角点
    float roiWidth = width;
    float roiHeight = height;
    cv::Point2f widthDir(cos(angle), sin(angle));

    std::vector<cv::Point2f> roiCorners = {
            roiCenter - widthDir * (roiWidth/2) - perpendicularDir * (roiHeight/2),
            roiCenter + widthDir * (roiWidth/2) - perpendicularDir * (roiHeight/2),
            roiCenter + widthDir * (roiWidth/2) + perpendicularDir * (roiHeight/2),
            roiCenter - widthDir * (roiWidth/2) + perpendicularDir * (roiHeight/2)
    };

//     // 5. 绘制时需要转换为整数坐标
//     std::vector<cv::Point> roiCornersInt;
//     for (const auto& pt : roiCorners) {
//     roiCornersInt.emplace_back(cvRound(pt.x), cvRound(pt.y));
//     }
//     cv::polylines(m_markedImage, std::vector<std::vector<cv::Point>>{roiCornersInt},
//     true, cv::Scalar(0, 0, 255), 1);

    // 6. 透视变换
    std::vector<cv::Point2f> dstCorners = {
            {0, 0}, {roiWidth, 0}, {roiWidth, roiHeight}, {0, roiHeight}
    };
    cv::Mat perspMat = cv::getPerspectiveTransform(roiCorners, dstCorners);
    cv::warpPerspective(m_markedImage, m_extractedROIs.emplace_back(),
                        perspMat, cv::Size(roiWidth, roiHeight));

    perspMat.release();
}

std::vector<cv::Point> QRPickDetector::processSingleQROffInstance(
        const std::vector<cv::Point>& qrCorners,
        const double& offset,
        const double& width,
        const double& height,
        const int& index)
{
    // 1. 输入验证
    if (qrCorners.size()  != 4)  {
        std::cerr << "Error: Invalid input parameters" << std::endl;
        return {};
    }

    // 2. 转换为浮点坐标
    std::vector<cv::Point2f> qrCornersFloat;
    for (const auto& pt : qrCorners) {
        qrCornersFloat.emplace_back(pt.x,  pt.y);
    }

    // 3. 确定基准边（取底部两个角点）
    const cv::Point2f& bottomLeft = qrCornersFloat[3]; // 假设顺序为左下→右下→右上→左上
    const cv::Point2f& bottomRight = qrCornersFloat[2];

    // 4. 计算几何参数
    cv::Point2f baseVec = bottomRight - bottomLeft;
    float angle = atan2(baseVec.y, baseVec.x);
    cv::Point2f perpendicularDir(-sin(angle), cos(angle)); // 指向二维码内部
    cv::Point2f baseMid = (bottomLeft + bottomRight) * 0.5f;
    cv::Point2f roiCenter = baseMid + perpendicularDir * (offset);

    // 4. 计算ROI角点
    float roiWidth = width;
    float roiHeight = height;
    cv::Point2f widthDir(cos(angle), sin(angle));

    std::vector<cv::Point2f> roiCorners = {
            roiCenter - widthDir * (roiWidth/2) - perpendicularDir * (roiHeight/2),
            roiCenter + widthDir * (roiWidth/2) - perpendicularDir * (roiHeight/2),
            roiCenter + widthDir * (roiWidth/2) + perpendicularDir * (roiHeight/2),
            roiCenter - widthDir * (roiWidth/2) + perpendicularDir * (roiHeight/2)
    };

     // 5. 绘制时需要转换为整数坐标
     std::vector<cv::Point> roiCornersInt;
     for (const auto& pt : roiCorners) {
        roiCornersInt.emplace_back(cvRound(pt.x), cvRound(pt.y));
     }

    if (index == 0){ // 红色 C
        cv::polylines(m_markedImage, std::vector<std::vector<cv::Point>>{roiCornersInt},true, cv::Scalar(0, 0, 255), 1);
    } else if (index == 1){ // 绿色 T
        cv::polylines(m_markedImage, std::vector<std::vector<cv::Point>>{roiCornersInt},true, cv::Scalar(0, 255, 0), 1);
    } else { // 蓝色
        cv::polylines(m_markedImage, std::vector<std::vector<cv::Point>>{roiCornersInt},true, cv::Scalar(255, 0, 0), 1);
    }

    return roiCornersInt;
}

// Getter 实现
const std::vector<double>& QRPickDetector::getQrSideLengths() const {
    return m_qrSideLengths;
}

const cv::Mat& QRPickDetector::getExtractedROIs(int index) const {
    return m_extractedROIs[index];
}

const cv::Mat& QRPickDetector::getMarkedImage() const {
    return m_markedImage;
}

const std::vector<std::vector<cv::Point>>& QRPickDetector::getAllQrCorners() const {
    return m_allQrCorners;
}

const std::vector<std::string>& QRPickDetector::getQrContents() const {
    return m_qrContents;
}